﻿/********************************************************************************
* Copyright 2010 Zane Thorn (zane.thorn@gmail.com)                              *
*                                                                               *
* NeturalMath is free software: you can redistribute it and/or modify           *
* it under the terms of the GNU Lesser General Public License as published by   *
* the Free Software Foundation, either version 3 of the License, or             *
* (at your option) any later version.                                           *
*                                                                               *
* NeturalMath is distributed in the hope that it will be useful,                *
* but WITHOUT ANY WARRANTY; without even the implied warranty of                *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
* GNU Lesser General Public License for more details.                           *
*                                                                               *
* You should have received a copy of the GNU Lesser General Public License      *
* along with NeturalMath.  If not, see <http://www.gnu.org/licenses/>.          *
********************************************************************************/

//#define DIAGNOSTICS

using System;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using MathConsole.Properties;
using NeturalMath;

namespace MathConsole
{
    public class ConsoleInterpreter:ConsoleInterface
    {
        public static readonly string EXIT = @"^(?i)exit\s*";
        public static readonly string EDIT = @"^(?i)edit\s*";
        public static readonly string RUN = @"^(?i)run\s";
        public static readonly string CLEAR = @"^(?i)clear\s*";
        public static readonly string RESET = @"^(?i)reset\s*";
        public static readonly string HELP = @"^(?i)help\s*";
        public static readonly string SAVE = @"^(?i)save\s*";
        public static readonly string OPEN = @"^(?i)open\s*";

        private static readonly Regex EDIT_REGEX = new Regex(EDIT);
        private static readonly Regex EXIT_REGEX = new Regex(EXIT);
        private static readonly Regex RUN_REGEX = new Regex(RUN);
        private static readonly Regex CLEAR_REGEX = new Regex(CLEAR);
        private static readonly Regex RESET_REGEX = new Regex(RESET);
        private static readonly Regex HELP_REGEX = new Regex(HELP);
        private static readonly Regex SAVE_REGEX = new Regex(SAVE);
        private static readonly Regex OPEN_REGEX = new Regex(OPEN);

        public override bool Read()
        {
            var domain = Program.Runtime.CurrentDomain;
            for (int i = 1; i <= domain.Depth; i++)
                Console.Write(".");
            Console.Write(":>");
            var line = Console.ReadLine();

            if (string.IsNullOrWhiteSpace(line))
                return true;

            return EvaluateCommands(line);
        }

        public  bool EvaluateCommands(string input)
        {
#if !DEBUG
            try
            {
#endif
            if (EXIT_REGEX.IsMatch(input))
                return false;
            else if (RUN_REGEX.IsMatch(input))
                RunFile(input);
            else if (HELP_REGEX.IsMatch(input))
                DisplayHelp(input);
            else if (CLEAR_REGEX.IsMatch(input))
                Clear();
            else if (RESET_REGEX.IsMatch(input))
                Reset();
            else if (EDIT_REGEX.IsMatch(input))
                Program.SwitchToEditor();
            else if (SAVE_REGEX.IsMatch(input))
                Save(SAVE_REGEX.Replace(input,string.Empty));
            else if (OPEN_REGEX.IsMatch(input))
                Open(input);
            else
                InterpretInput(input);
#if !DEBUG
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.WriteLine(Resources.IgnoreLine);
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);
                Console.ForegroundColor = ConsoleColor.White;
            }
#endif
            return true;
        }

        public  void Reset()
        {
            Program.Runtime.ResetRoot();
        }

        public  void Clear()
        {
            Console.Clear();
        }

        private  void InterpretInput(string input)
        {
#if DIAGNOSTICS
            var watch = new Stopwatch();
            watch.Start();
#endif
            var result = Program.Runtime.ExecuteText(input);
            if (result!=Program.Runtime.Void)
                Console.WriteLine(result.GetValue());

            Buffer.Add(input);

#if DIAGNOSTICS
            watch.Stop();
            Console.WriteLine(string.Format("Parse Time(ms): "+watch.ElapsedMilliseconds));
#endif
        }


        private  void RunFile(string input)
        {
            var parts = RUN_REGEX.Split(input);
            var pathString = parts[1].Trim();

            if (!File.Exists(pathString))
                throw new ArgumentException(string.Format("Path '{0}' does not exist", pathString));

            Program.Runtime.ExecuteFile(pathString);
        }
    }
}
